﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EpcTagLibrary.Pat
{
    public abstract class Pattern : EPC
    {
        private GroupField m_Parent = new GroupField(null);
        private IList<GroupField> m_Leaves = new List<GroupField>();
        private PatternField[] m_Fields;
        private Type m_Type;
        private string m_Uri;
        private bool m_Grouping;
        private bool m_PureId;

        public Pattern(PatternField[] fields, Type type)
            : base(new byte[0])
        {
            m_Fields = fields;
            m_Type = type;
        }

        public PatternField[] Fields
        {
            get
            {
                return m_Fields;
            }
        }

        public Type Type
        {
            get
            {
                return m_Type;
            }
        }

        public bool Match(EPC epc)
        {
            if (epc.GetType() != Type)
            {
                return false;
            }

            if (!m_PureId && (epc.GetTagBitLength() != GetTagBitLength()))
            {
                return false;
            }

            foreach (PatternField Field in Fields)
            {
                if (!Field.MatchField(epc))
                {
                    return false;
                }
            }

            return true;
        }

        public bool Group(EPC epc)
        {
            if (epc.GetType() != GetType())
            {
                return false;
            }

            if (!m_PureId && (epc.GetTagBitLength() != GetTagBitLength()))
            {
                return false;
            }

            GroupField Parent = m_Parent;

            foreach (PatternField Field in Fields)
            {
                Parent = Field.GroupField(epc, Parent);

                if (Parent == null)
                {
                    return false;
                }
            }

            Parent.AddEpc(epc);

            if (!m_Leaves.Contains(Parent))
            {
                m_Leaves.Add(Parent);
            }

            return true;
        }

        public GroupField GroupData
        {
            get
            {
                return m_Parent;
            }
        }

        public bool IsGrouping
        {
            get
            {
                return m_Grouping;
            }
            set
            {
                m_Grouping = value;
            }
        }

        public bool IsPureId
        {
            get
            {
                return m_PureId;
            }
            set
            {
                m_PureId = value;
            }
        }

        public IList<GroupField> Leaves
        {
            get
            {
                return m_Leaves;
            }
        }

        public string Uri
        {
            get
            {
                return m_Uri;
            }
            set
            {
                m_Uri = value;
            }
        }

        public override Uri GetEPC()
        {
            return new Uri(Uri);
        }

        public override Uri GetTag()
        {
            return GetEPC();
        }

        public RAW ToRawType()
        {
            return null;
        }

        public override int[] GetFieldSplits()
        {
            return new int[0];
        }

        public override string ToString()
        {
            return Uri;
        }

        public override int GetHashCode()
        {
            return Uri.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return true;
            }

            if ((obj == null) || !(obj is Pattern))
            {
                return false;
            }

            Pattern Pat = obj as Pattern;

            return Uri != null ? Uri.Equals(Pat.Uri) : Pat.Uri != null;
        }
    }
}
